<?php
/**
 * 缓存
 * User: dxk
 * Date: 2020/07/15
 */
namespace App\Traits;

use App\Library\Service\DB\TransactionMonitorService;
use App\Service\EasyCache;

trait CacheTrait
{
    private bool $debug = false;//缓存调试模式
    private int $cache_time = 600;//缓存时间
    private string $cache_prefix = 'cache_';//缓存前缀
    private static array $var_cache = [];//静态变量缓存

    /**
     * 清理缓存$cache_k
     * @param string $cache_k 缓存key 不用带$this->cache_prefix
     * @return bool
     */
    protected function cleanCache(string $cache_k): bool
    {
        $cache_k = trim($cache_k);
        $cache_k = strtolower($cache_k);
        if (empty($cache_k)) {
            return false;
        }
        $cache_k = $this->cache_prefix . $cache_k;
        self::delVarCache($cache_k);
        TransactionMonitorService::transCache($this->cacheInstance(), $cache_k);
        return $this->cacheInstance()->forget($cache_k);
    }

    /**
     * 从缓存中存取数据
     * @param string $cache_k 缓存key 不用带$this->cache_prefix
     * @param \Closure $obj 如果缓存中取不到数据会获取此函数的返回值
     * @param bool $is_cache 是否从缓存中读取数据
     * @param bool $cache_empty_value 是否缓存空数据（比如查询一个不存在的商品，默认不开启）
     * @param bool $use_var_cache 是否启用变量缓存（在循环导出时打开此值会提升效率，直接从内存变量获取数据，默认不开启）
     * @return array
     */
    protected function cache(string $cache_k, \Closure $obj, bool $is_cache = true, bool $cache_empty_value = false, bool $use_var_cache = false): array
    {
        $cache_k = trim($cache_k);
        $cache_k = strtolower($cache_k);
        if (empty($cache_k)) {
            return [];
        }
        $cache_k = $this->cache_prefix . $cache_k;
        if ($use_var_cache) {
            $val = self::getVarCache($cache_k);
            if (!empty($val)) {
                return $val;
            }
        }
        if ($is_cache === true && $this->debug === false) {
            $val = $this->cacheInstance()->get($cache_k);
        } else {
            $val = null;
        }
        if (is_null($val) || (!$cache_empty_value && empty($val)) || $this->debug || !$is_cache) {
            //需要重新取值的情况
            $val = $obj();
            if (!empty($val) || $cache_empty_value) {
                if (!TransactionMonitorService::isTransaction()) {
                    $this->cacheInstance()->put($cache_k, $val, $this->cache_time);
                } else {
                    //如果开启了事务，此时如果不更新缓存，如果之后是rollback没问题，如果是commit则缓存是错的，所以，如果开启了事务要清理缓存
                    self::cleanCache($cache_k);
                }
            }
        }
        if ($use_var_cache) {
            self::setVarCache($cache_k, $val);
        }
        return $val;
    }

    /**
     * 缓存对象
     * @return \Illuminate\Cache\Repository
     * @throws \Exception
     */
    private function cacheInstance(): object
    {
        static $cache = null;
        if (isset($cache)) {
            return $cache;
        }
//        if ($this->debug) {
//            $instance = DebugCache::getInstance();
//        } else {
        $instance = EasyCache::getCache();
//        }
        $cache = $instance;
        return $instance;
    }

    /**
     * 从变量缓存中存取数据
     * @param string $cache_k 缓存key 不用带$this->cache_prefix
     * @param \Closure $obj 如果缓存中取不到数据会获取此函数的返回值
     * @return mixed
     */
    protected function varCache(string $cache_k, \Closure $obj): mixed
    {
        $cache_k = trim($cache_k);
        $cache_k = strtolower($cache_k);
        if (empty($cache_k)) {
            return false;
        }
        $cache_k = $this->cache_prefix . $cache_k;
        $val = self::getVarCache($cache_k);
        if (!is_null($val)) {
            return $val;
        }
        $val = $obj();
        self::setVarCache($cache_k, $val);
        return $val;
    }

    /**
     * 变量缓存
     * @param $cache_k
     * @param $val
     * @return bool
     */
    protected static function setVarCache($cache_k, $val): bool
    {
        if (!defined('IS_WEB') || IS_WEB != 1) {
            return false;
        }
        if (count(static::$var_cache) >= 300) {
            reset(static::$var_cache);
            self::delVarCache(array_key_first(static::$var_cache));
        }
        static::$var_cache[$cache_k] = $val;
        return true;
    }

    /**
     * 获取变量缓存
     * @param $cache_k
     * @return mixed
     */
    protected static function getVarCache($cache_k): mixed
    {
        return static::$var_cache[$cache_k] ?? null;
    }

    /**
     * 清理变量缓存
     * @param $cache_k
     */
    protected static function delVarCache($cache_k)
    {
        unset(static::$var_cache[$cache_k]);
    }
}
